# category.py
# Original Author: Amar Zumkhawala (amarzumkhawala@gmail.com)
# Project URL - http://code.google.com/p/feedflare-categories
# Distributed under Apache License 2.0
#
# $Revision: 36 $, $Date: 2009-01-13 00:03:32 +0000 (Tue, 13 Jan 2009) $
# $Author: amarzumkhawala $

import logging
import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template

from atom import AtomEntry, AtomEntryParser
from blogservice import BlogEntry
from bloggerdotcom import BloggerDotComService
from testblogservice import TestBlogService
from testrssblogservice import TestRssBlogService
from feedflarexml import FeedFlareXmlBuilder
from usagestats import UsageStatisticsService
from wordpress import WordpressService
from rsstoatom import RssToAtom

class MainPage(webapp.RequestHandler):
  """
  If there are request parameters, service the request.  Otherwise
  return an html page with info about this application.
  """
  def get(self):
    id = self.request.get('id')
    generator = self.request.get('generator')

    logging.info("id = '%s' and generator = '%s'", id, generator)

    if (len(id) == 0 and len(generator) == 0):
      path = os.path.join(os.path.dirname(__file__), 'index.html')
      self.response.out.write(template.render(path, None))
    else:
      self.flare(id, generator)

  """
  Our flare() method complies with the API requirements
  for the Feedburner FeedFlare type 'DynamicFlare.'

  Upon an error, a default FeedFlare text is returned.
  """
  def flare(self,id,generator):
    self.response.headers['Content-Type'] = 'text/plain'
    try:
      # factory service class based on feed generator (e.g. blogger, wordpress)
      blogService = BlogServiceFactory.factory(id, generator)
     
      # fetch original blog feed
      blogEntry = blogService.blogEntry()
      blogXml = blogService.fetchBlogXml(blogEntry)

      converter = RssToAtom()

      # convert to atom from rss, if necessary
      isRss = converter.isRss(blogXml)
      if (isRss != 0):
        atomXml = converter.convert(blogXml)
      else:
        atomXml = blogXml

      # parse the atom xml for the categories and blog url of the entry with the given id
      atomEntryParser = AtomEntryParser()
      atomEntry = atomEntryParser.parse(blogEntry.atomId(), atomXml)

      # build the xml for the FeedFlare
      feedFlareXmlBuilder = FeedFlareXmlBuilder()
      feedFlareXml = feedFlareXmlBuilder.build(blogService, atomEntry)

      logging.debug(feedFlareXml)

      self.response.out.write(feedFlareXml)
    except Exception:
      logging.exception("got exception...")
      # error, so just emit an default FeedFlare
      self.response.out.write("<FeedFlare><Text></Text></FeedFlare>")
    else:
      try:
        # success! so record usage of our service
        atomId = blogEntry.atomId()
        blogurl = atomEntry.blogUrl()
        usageStatisticsService = UsageStatisticsService()
        usageStatisticsService.record(atomId,blogurl)
      except Exception:
        logging.exception("Exception during usage statistics logging")
  
application = webapp.WSGIApplication(
                                     [('/', MainPage)],
                                     debug=True)

"""Tiny wrapper to enable a method to be callable"""
class Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

"""Factory Class For Blog Service instances"""
class BlogServiceFactory:
  """Factory appropriate blog service class for the given generator,
  constructing the instance with the given id.
  """
  def factory(id, generator):    
    if generator == "test":
      blogService = TestBlogService()
    elif generator == "rsstest": 
      blogService = TestRssBlogService()
    elif (generator.find("wordpress") > 0):
      blogService = WordpressService(id)
    elif generator == "Blogger":
      blogService = BloggerDotComService(id)
    else:
      blogService = BloggerDotComService(id)

    return blogService

  # bind our factory method to an instance
  factory = Callable(factory)

"""Main for application"""
def real_main():
  run_wsgi_app(application)

"""Main for profiling"""
def profile_main():
 # This is the main function for profiling.
 # We've renamed our original main() above to real_main()
 import cProfile, pstats
 prof = cProfile.Profile()
 prof = prof.runctx("real_main()", globals(), locals())
 print "<pre>"
 stats = pstats.Stats(prof)
 stats.sort_stats("time")  # Or cumulative
 stats.print_stats(80)  # 80 = how many to print
 # The rest is optional.
 # stats.print_callees()
 # stats.print_callers()
 print "</pre>"

main = real_main
if __name__ == "__main__":
  main()
